/**
 * 拦截uploadFile文件上传、http接口请求
 */

import { useMemberStore } from '@/stores'
import { Md5 } from 'ts-md5'

// 生产环境URL
const PROD_BASE_URL = 'http://192.168.74.1:9988'
// 开发环境URL
const DEV_BASE_URL = 'http://192.168.74.1:9988'
// appId
const appId = '1000'
// appSecret
const appSecret = 'ncqa9b6nzaemgvy8wg2m2euu'

// 添加拦截器
const httpInterceptor = {
  // 拦截前触发
  invoke(options: UniApp.RequestOptions) {
    let formattedData = ''
    const timestamp = new Date().getTime()
    if (options.data !== undefined) {
      const jsonData = JSON.stringify(options.data)
      // 将 JSON 字符串转换为对象，并按照 key 的升序排列
      const sortedData: { [key: string]: any } = JSON.parse(jsonData)
      const sortedKeys = Object.keys(sortedData).sort()
      // 按照 key=value 的格式拼接键值对
      formattedData = sortedKeys.map((key) => `${key}=${sortedData[key]}`).join('&')
      formattedData += '&'
    }
    formattedData += 'timestamp=' + timestamp + '&appSecret=' + appSecret
    const sign = Md5.hashStr(formattedData)
    if (import.meta.env.DEV) {
      options.url = DEV_BASE_URL + options.url
    } else {
      options.url = PROD_BASE_URL + options.url
    }
    // 请求超时时间，配置10s
    options.timeout = 10000
    // header处理，token，sign
    options.header = {
      ...options.header,
    }
    const memberStore = useMemberStore()
    const token = memberStore.profile?.token
    if (token) {
      options.header.Authorization = token
      options.header.token = token
    }
    options.header.timestamp = timestamp
    options.header.appId = appId
    options.header.sign = sign
  },
}

uni.addInterceptor('request', httpInterceptor)
uni.addInterceptor('uploadFile', httpInterceptor)

/**
 * 封装请求函数
 * uni.request请求成功返回的是一个Promise对象，对象中包含了：cookies、errMsg、statusCode、data等
 * 其中，data才是我们需要的服务器返回的数据，对请求函数进行封装，只要其中服务器的数据
 * 1.请求成功
 *  1.1.提取核心数据，res.data
 *  1.2.添加类型，支持泛型
 * 2.请求失败
 *  2.1.网络错误 -> 提示用户切换网络
 *  2.2.401错误 -> 清理用户信息，跳转到登录页
 *  2.3.其他错误 -> 根据后端错误信息提示
 */
export const http = <T>(options: UniApp.RequestOptions) => {
  // 1.返回Promise对象
  return new Promise<BaseResponse<T>>((resolve, reject) => {
    uni.request({
      ...options,
      // 请求成功
      success(res) {
        if (res.statusCode >= 200 && res.statusCode < 300) {
          // 提取核心数据res.data，断言类型为Data<T>
          if ((res.data as BaseResponse<T>).code == 200) {
            resolve(res.data as BaseResponse<T>)
          } else {
            // 业务层面错误，根据后端错误提示
            uni.showToast({
              icon: 'none',
              title: (res.data as BaseResponse<T>).message || '请求错误',
            })
            reject(res)
          }
        } else if (res.statusCode === 401) {
          // 401错误，导航到登录页
          const memberStore = useMemberStore()
          memberStore.clearProfile()
          uni.navigateTo({ url: 'pages/login/login' })
          reject(res)
        } else {
          // 其他错误，根据后端错误提示
          uni.showToast({
            icon: 'none',
            title: (res.data as BaseResponse<T>).message || '请求错误',
          })
          reject(res)
        }
      },
      // 请求失败
      fail(err) {
        // 网络错误
        uni.showToast({
          icon: 'none',
          title: '网络错误，换个网络试试',
        })
        reject(err)
      },
    })
  })
}
interface BaseResponse<T> {
  code: number
  message: string
  data: T
}
